#ifndef __MY_DATA__
#define __MY_DATA__ 
#include <unordered_map>
#include "util.hpp"

namespace cloud
{
  //文件信息结构
  typedef struct _FileInfo
  {
    std::string filename;//纯文件名
    std::string url_path;//下载链接路径
    std::string real_path;//实际存储路径
    size_t file_size;//文件大小
    time_t back_time;// 最后一次修改时间，即备份时间
    bool pack_flag;//是否压缩的标志
    std::string pack_path;//压缩包路径名
  }FileInfo;

  class DataManager
  {
    private:
      std::string  _back_dir = "./backup_dir/";//备份文件实际存储的路径
      std::string _pack_dir = "./pack_dir/";//压缩包存储路径
      std::string _download_prefix = "/download/";//下载链接的前缀路径
      std::string _pack_subfix = ".zip";//压缩包后缀名
      std::string _back_info_file = "./backup.dat";//存储备份信息的文件，持久化存储所有历史备份信息的文件
      //用url作为key，是因为当前端下载文件时，就会发送过来url
      std::unordered_map<std::string, FileInfo> _back_info;//<url, fileinfo> 备份信息的哈希管理
    public:
      DataManager()//构造函数
      {
        FileUtil(_back_dir).CreateDirectory();//创建备份文件实际存储路径目录
        FileUtil(_pack_dir).CreateDirectory();//创建压缩包存储路径目录
        if(FileUtil(_back_info_file).Exists())//是否备份文件存在,存在则加载
        {
          InitLoad();
        }
      }
      bool InitLoad()//初始化,当模块运行起来之后第一时间将历史信息读取出来存储到hash表中
      {
        //1.读取文件中的历史备份信息
        std::string body;
        bool ret = FileUtil(_back_info_file).Read(&body);//将存储备份信息的文件读取数据到body中
        if(ret == false)//如果找不到存储备份信息的文件，输出对应提示语句
        {
          std::cout << "load history failed\n";
          return false;
        }
        //2.对读取的信息进行反序列化
        Json::Value infos;//这里的infos实际上是从文件中读取后进行反序列化的Json::Value对象，实际上内部是一个数组，数组中有一个一个的备份信息
        ret = JsonUtil::UnSerialize(body,&infos);//将body中的数据反序列存储到infos之中
        if(ret == false)
        {
          std::cout << "initload parse history failed\n";
          return false;
        }
        //3.将反序列化得到的数据存储到hash表中 
        int sz = infos.size();
        for(int i=0;i<sz;i++)
        {
          FileInfo info;//info为结构体变量
          info.filename = infos[i]["filename"].asString();
          info.url_path = infos[i]["url_path"].asString(); 
          info.real_path = infos[i]["real_path"].asString(); 
          info.file_size = infos[i]["file_size"].asInt64();  
          info.back_time = infos[i]["back_time"].asInt64();                
          info.pack_flag = infos[i]["pack_flag"].asBool();
          info.pack_path = infos[i]["pack_path"].asString();
          _back_info[info.url_path] = info; //下载链接作为key，info作为value
        }
        return true;
      }
      bool Storage()//持久化存储,逐个获取信息然后将信息添加到infos之中去
      {
        Json::Value infos;
        std::vector<FileInfo> arry;
        this->SelectAll(&arry);//获取所有信息
        for(auto &a :arry)
        {
          //把之前获取到的所有信息传入到infos中
          Json::Value info;
          info["filename"] = a.filename; 
          info["url_path"] =  a.url_path; 
          info["real_path"] =  a.real_path; 
          info["file_size"] =  (Json::UInt64)a.file_size; 
          info["back_time"] =  (Json::UInt64)a.back_time; 
          info["pack_flag"] =  a.pack_flag;
          info["pack_path"] =  a.pack_path;
          infos.append(info);//添加json：：value的数组元素
        }
        std::string body;
        JsonUtil::Serialize(infos, &body);//将infos序列化为body字符串
        FileUtil(_back_info_file).Write(body);//将body数据写入到存储备份信息的文件之中
        return true;

      }
      //数据的增删改查
      // 增：输入一个文件名，在接口中获取各项信息，生成压缩包名称，填充结构体，压如hash表
      bool Insert(const std::string &pathname)//pathname为文件路径
      {
        if(FileUtil(pathname).Exists() ==false)
        {
          std::cout << "insert file is not exists\n";//检验文件是否存在
          return false;
        }
        // pathname = ./backup_dir/a.txt
        FileInfo info;
        info.filename = FileUtil(pathname).Name();//获取到a.txt
        // 下载链接前缀路径+纯文件名,获取到/download/a.txt,下载链接的资源路径
        info.url_path = _download_prefix + info.filename;
        info.real_path = pathname;// 实际存储路径./backup_dir/a.txt
        info.file_size = FileUtil(pathname).Size();//文件大小
        info.back_time = FileUtil(pathname).MTime();//最后一次修改时间就是备份时间
        info.pack_flag = false;//刚上传的文件都是非压缩状态
        //压缩包路径名_pack_dir/a.txt.zip
        info.pack_path = _pack_dir +info.filename + _pack_subfix;//压缩包存储路径+文件名+压缩包后缀
        _back_info[info.url_path] = info;//以url_path为key，info为value添加到map中
        Storage();//新增完毕一次就存储一次
        return true;
      }
      // 改--1.上传备份，添加信息，当文件压缩存储了要修改压缩标志，下载解压后，也修改压缩路径
      bool UpdataStatus(const std::string &pathname,bool status)
      {
        std::string url_path = _download_prefix + FileUtil(pathname).Name();// 下载链接前缀+纯文件名
        auto it = _back_info.find(url_path);//在map中根据查找下载链接资源路径进行查找
        if(it == _back_info.end())
        {
          std::cout << "files info is not exists\n";//没找到
          return false;
        }
        it->second.pack_flag = status;//状态的修改,因为url_path是key，所以info则是value即指向second
        Storage();//修改完了存储一次
        return true;
      }
      // 查：查询所有备份信息（前端展示界面需要-文件名，下载链接，大小，备份时间）
      //     查询单个文件信息(文件下载-获取文件实际备份路径) 
      bool SelectAll(std::vector<FileInfo> *infos)
      {
        for(auto it = _back_info.begin();it != _back_info.end(); it++ )
        {
          infos->push_back(it->second);//添加备份信息
        }
        return true;
      }
      //通过key也就是url_path下载链接来获取备份信息
      bool SelectOne(const std::string &url_path, FileInfo *info)
      {
        auto it = _back_info.find(url_path);
        if(it == _back_info.end())
        {
          std::cout << "selectone files info is not exists\n";//没找到
          return false;
        }
        *info = it->second;//把单个文件信息的所有信息返回回去
        return true;
      }
      //通过实际路径来获取备份信息
      bool SelectOneByRealpath(const std::string &real_path, FileInfo *info)
      {
        for(auto it = _back_info.begin();it != _back_info.end();it++)
        {
          if(it->second.real_path == real_path)
          {
            *info = it->second;//将找到的数据填充到info中
            return true;
          }
        }
        return false;
      }
      // 删：基本备份的文件都不删除（防备功能扩展）
      bool DeleteOne(const std::string &url_path)
      {  
        auto it = _back_info.find(url_path);//指定查找对应文件
        if(it == _back_info.end())
        {
          std::cout << "files info is not exists\n";//没找到
          return false;
        }
        _back_info.erase(it);//先找到要删除的，再利用迭代器删除
        Storage();//删除完成之后存储一次
        return true;
      }
  };
}

#endif 
